import { BaseService } from '@/core/base.service';
import { Process, Processor } from '@nestjs/bull';
import { Job } from 'bull';
import { AssetAutoTrading } from '@prisma/client';
import { TokenLogTypeEnum, TokenStatusEnum } from '@/enums';
import dayjs from 'dayjs';
import { random, sleep } from 'radash';
import { halt } from '@/utils';
import { Logger } from '@nestjs/common';

@Processor('autotrading')
export class AutotradingProcessor extends BaseService {
  @Process('sale')
  async sale(job: Job) {
    const time = dayjs().format('YYYY-MM-DD HH:mm:ss');
    const await_lock = await this.redis.exists(
      'bull:autotrading:repeat:await_lock',
    );
    if (await_lock) {
      //  Logger.debug('!!!!!!!!!!!!!!!!!!消费队列:挂售进行中' + await_lock);
      return {};
    }
    await this.redis.setex('bull:autotrading:repeat:await_lock', 60, time);

    const list = await this.prisma.assetAutoTrading.findMany({
      where: {
        status: true,
      },
    });

    if (list.length > 0) {
      for (const item of list) {
        // Logger.debug(`${item.assetId}:开始挂售`);

        if (item.isStop) {
          //  Logger.debug(`${item.assetId}:暂停中`);
          // Logger.debug(`${item.assetId}:结束挂售`);
          continue;
        }
        if (!item.isIgnore) {
          // 不忽略用户挂单
          const userSaleCount = await this.prisma.token.count({
            where: {
              assetId: item.assetId,
              ownerId: { not: item.sellerId },
              status: TokenStatusEnum.ON_SALE,
            },
          });

          if (userSaleCount > 0) {
            //  Logger.debug(
            //     `${item.assetId}:不忽略用户挂单，用户挂单>0，挂售下一个藏品`,
            //   );
            // Logger.debug(`${item.assetId}:结束挂售`);
            continue;
          }
        }

        // const currentTime = dayjs();
        // Logger.debug('当前时间' + currentTime.format('YYYY-MM-DD HH:mm:ss'));

        const sNextWait = await this.redis.exists(
          'bull:autotrading:repeat:sale:' + item.assetId + ':sleep',
        );
        if (sNextWait) {
          const ttl = await this.redis.ttl(
            'bull:autotrading:repeat:sale:' + item.assetId + ':sleep',
          );
          // 如果有下一次上架时间
          //  Logger.debug(`${item.assetId}:上架时间未到达，剩余${ttl}s`);
          // Logger.debug(`${item.assetId}:结束挂售`);
          continue;
          // return {};
        } else {
          // 如果没有下一次上架时间，生成一个时间
          //  Logger.debug(`${item.assetId}:无上架等待时间，查询同时上架数量`);
          const lockingCount = await this.prisma.token.count({
            where: {
              status: TokenStatusEnum.LOCKING,
              ownerId: item.sellerId,
              assetId: item.assetId,
            },
          });
          if (lockingCount >= item.onceTime) {
            //  Logger.debug(
            //     `${item.assetId}:同时存在数量${lockingCount}≥设定值${item.onceTime}，挂售下一个藏品`,
            //   );
            // Logger.debug(`${item.assetId}:结束挂售`);
            continue;
          }
          //  Logger.debug(
          //     `${item.assetId}:########################开始上架########################`,
          //   );
          const saleTokenId = await this.redis.spop(
            'autotarding:' + item.assetId + ':ids',
          );
          if (saleTokenId == null) {
            //  Logger.debug(`${item.assetId}:挂售队列为空，重置队列`);
            await this.redis.del('autotarding:' + item.assetId + ':ids');
            const aQueueMembers = await this.redis.smembers(
              'autotarding:' + item.assetId + ':queue',
            );

            if (aQueueMembers.length <= 0) {
              //  Logger.debug(`${item.assetId}:源队列为空，重置失败`);
              // Logger.debug(`${item.assetId}:结束挂售`);
              continue;
            }

            await this.redis.sadd(
              'autotarding:' + item.assetId + ':ids',
              ...aQueueMembers,
            );
            //  Logger.debug(`${item.assetId}:队列重置完成`);
            // Logger.debug(`${item.assetId}:结束挂售`);
            continue;
          }

          //  Logger.debug(`${item.assetId}:资产ID：${saleTokenId}`);
          // 开始上架，并生成下次上架时间
          try {
            await this.prisma.token.update({
              where: {
                id: Number(saleTokenId),
                status: TokenStatusEnum.HOLD,
                ownerId: item.sellerId,
                assetId: item.assetId,
              },
              data: {
                status: TokenStatusEnum.LOCKING,
                price: random(Number(item.minPrice), Number(item.maxPrice)),
              },
            });
          } catch (error) {
            //  Logger.debug(
            //     `${item.assetId}:########################上架失败########################`,
            //   );
            // Logger.debug(`${item.assetId}:结束挂售`);
            continue;
          }

          //  Logger.debug(
          //     `${item.assetId}:########################上架成功########################`,
          //   );

          //  Logger.debug(`${item.assetId}:设置下次上架时间`);
          await this.redis.setex(
            'bull:autotrading:repeat:sale:' + item.assetId + ':sleep',
            random(5, 10),
            1,
          );

          const waitTime = item.waitTime + random(5, 15);
          //  Logger.debug(
          //     `${item.assetId}:设置${item.assetId}挂售维持时间${waitTime}s`,
          //   );
          await this.redis.setex(
            `autotarding:${item.assetId}:wait_down:${saleTokenId}`,
            waitTime,
            1,
          );
          // Logger.debug(`${item.assetId}:结束挂售`);
        }
      }
    } else {
      //  Logger.debug(`无挂售任务`);
    }
    await this.redis.del('bull:autotrading:repeat:await_lock');
    return {};
  }

  @Process('buy')
  async buy(job: Job) {
    // console.log('消费队列:买入/下架');
    const time = dayjs().format('YYYY-MM-DD HH:mm:ss');
    const buy_lock = await this.redis.exists(
      'bull:autotrading:repeat:buy_lock',
    );
    if (buy_lock) {
      //  Logger.debug('!!!!!!!!!!!!!!!!!!消费队列:买入/下架进行中' + buy_lock);
      return {};
    }
    await this.redis.setex('bull:autotrading:repeat:buy_lock', 60, time);

    const list = await this.prisma.assetAutoTrading.findMany({
      where: {
        status: true,
      },
    });

    if (list.length > 0) {
      for (const item of list) {
        // Logger.debug(`${item.assetId}:BUY:开始买入/下架`);

        // 获取挂售队列
        const aQueueMembers = await this.redis.smembers(
          'autotarding:' + item.assetId + ':queue',
        );

        if (aQueueMembers.length <= 0) {
          //  Logger.debug(`${item.assetId}:BUY:暂无交易队列`);
          // Logger.debug(`${item.assetId}:BUY:结束买入`);
          continue;
        }

        for (const tokenId of aQueueMembers) {
          // 判断是否存在锁定时间
          // Logger.debug(`${item.assetId}:BUY:资产ID：${tokenId}`);
          const buyLock = await this.redis.exists(
            `autotarding:${item.assetId}:wait_down:${tokenId}`,
          );

          if (buyLock) {
            const ttl = await this.redis.ttl(
              `autotarding:${item.assetId}:wait_down:${tokenId}`,
            );
            //  Logger.debug(`${item.assetId}:BUY:[${tokenId}]锁定中，剩余${ttl}s`);
            // Logger.debug(`${item.assetId}:BUY:结束买入`);
            continue;
          } else {
            try {
              // await this.prisma.$queryRawUnsafe<[]>(
              //   `
              //   UPDATE token
              //   SET status=${TokenStatusEnum.HOLD}
              //   WHERE id=${Number(tokenId)}
              //   AND status=${TokenStatusEnum.LOCKING}
              //   AND ownerId=${item.sellerId}
              //   AND assetId=${item.assetId}
              //   `,
              // );
              const token = await this.prisma.token.findUnique({
                where: {
                  id: Number(tokenId),
                  status: TokenStatusEnum.LOCKING,
                  ownerId: item.sellerId,
                  assetId: item.assetId,
                },
              });
              if (token) {
                //  Logger.debug(`${item.assetId}:BUY:[${tokenId}]更新下架`);
                await this.prisma.token.update({
                  where: {
                    id: Number(tokenId),
                    status: TokenStatusEnum.LOCKING,
                    ownerId: item.sellerId,
                    assetId: item.assetId,
                  },
                  data: {
                    status: TokenStatusEnum.HOLD,
                  },
                });

                //  Logger.debug(`${item.assetId}:BUY:[${tokenId}]插入log`);
                // token.price
                try {
                  await this.prisma.tokenLog.create({
                    data: {
                      log: `买入${token.price}￥`,
                      type: TokenLogTypeEnum.AUTOTRADING,
                      tokenId: token.id,
                      fromId: item.sellerId,
                    },
                  });
                } catch (e) {
                  console.error(e);
                }
              } else {
                // Logger.debug(`${item.assetId}:BUY:无需更新`);
                // Logger.debug(`${item.assetId}:BUY:结束买入`);
                continue;
              }
            } catch (e) {
              //  Logger.debug(`${item.assetId}:BUY:[${tokenId}]更新失败`);
              // Logger.debug(`${item.assetId}:BUY:结束买入`);
              continue;
            }
            //  Logger.debug(`${item.assetId}:BUY:[${tokenId}]更新成功`);
            // Logger.debug(`${item.assetId}:BUY:结束买入`);
          }
        }
      }
    } else {
      //  Logger.debug(`无买入/下架任务`);
    }

    await this.redis.del('bull:autotrading:repeat:buy_lock');
    return {};
  }
}
